<?php
namespace app\sysadmin\controller;

use Wy\Dir;
use Wy\Database as dbOper;
use think\Db;
use Env;
class Database extends Common{
	public function __construct(){
		parent::__construct();
		$this->backupPath = Env::get('root_path').'backup/'.trim(config('database.backup_path'), '/').'/';
	}
	// 数据库现有表
    public function index(){
		$tables = Db::query("SHOW TABLE STATUS");
		$this->assign('tables',$tables);
		return $this->fetch();
    }
	// 已备份数据库列表
	public function dblists(){
		//列出备份文件列表
		if(!is_dir($this->backupPath)){
			Dir::create($this->backupPath);
		}
		
		$flag = \FilesystemIterator::KEY_AS_FILENAME;
		$glob = new \FilesystemIterator($this->backupPath, $flag);
		$dataList = [];
		
		foreach ($glob as $name => $file) {
			if(preg_match('/^\d{8,8}-\d{6,6}-\d+\.sql(?:\.gz)?$/', $name)){
				$name = sscanf($name, '%4s%2s%2s-%2s%2s%2s-%d');
				$bak_name = "{$name[0]}{$name[1]}{$name[2]}-{$name[3]}{$name[4]}{$name[5]}";
				$date = "{$name[0]}-{$name[1]}-{$name[2]}";
				$time = "{$name[3]}:{$name[4]}:{$name[5]}";
				$part = $name[6];

				if(isset($dataList[$bak_name])){
					$info           = $dataList[$bak_name];
					$info['part']   = max($info['part'], $part);
					$info['size']   = $info['size'] + $file->getSize();
				}else{
					$info['part']   = $part;
					$info['size']   = $file->getSize();
				}

				$info['time']       = "{$date} {$time}";
				$extension          = strtoupper($file->getExtension());
				$info['compress']   = ($extension === 'SQL') ? '无' : $extension;
				$info['name']       = "{$date}_{$time}";;
				$info['id']         = $bak_name;
				$dataList[$bak_name] = $info;
			}
		}
		$this->assign('datalist',$dataList);
		return $this->fetch();
	}
	// 备份数据库
	public function export($id = 0, $start = 0){
		if($this->request->isPost()){
			$tables = array();
			$tables_lists = Db::query("SHOW TABLE STATUS");
			foreach ($tables_lists as $k => &$v) {
				$tables[] = $v['Name'];
			}
			 //读取备份配置
            $config = array(
                'path'     => $this->backupPath,
                'part'     => config('database.part_size'),
                'compress' => config('database.compress'),
                'level'    => config('database.compress_level'),
            );
			
			//检查是否有正在执行的任务
			$lock = $config['path'].'backup.lock';
			
			if($id == 0 && $start == 0){
				if(is_file($lock)){
					return $this->error('检测到有一个备份任务正在执行，请稍后再试');
				}else{
					if(!is_dir($config['path'])){
						Dir::create($config['path'], 0755, true);
					}
					//创建锁文件
					file_put_contents($lock, $this->request->time());
				}
				//生成备份文件信息
				$file = [
					'name' => date('Ymd-His', $this->request->time()),
					'part' => 1,
				];
				cache('back_sql_info',$file);
				
				$database = new dbOper($file, $config);
				if($database->create() !== false) {
					$table = $tables[$id];
					if(isset($tables[$id])){
						$table = $tables[$id];
					
						$start = $database->backup($table, $start);
						if($start == 0){
							$this->success('下一表','',array('id'=>($id+1),'start'=>0));
						}else{
							$this->success('下一步','',array('id'=>$id,'start'=>$start[0],'count'=>$start[1]));
						}
						
					}else{
						unlink($lock);
						$this->error('备份出错');
					}
				}else{
					unlink($lock);
					$this->error('备份成功');
				}
			}else{
				$file = cache('back_sql_info');
				
				if(isset($tables[$id])){
					$table = $tables[$id];
					
					$database = new dbOper($file, $config);
					$start = $database->backup($table, $start);
					if($start == 0){
						$this->success('下一表','',array('id'=>($id+1),'start'=>0));
					}else{
						$this->success('下一步','',array('id'=>$id,'start'=>$start[0],'count'=>$start[1]));
					}
				}else{
					unlink($lock);
					$this->error('备份成功');
				}
			}
			exit;
		}
		return $this->error('备份出错');
	}
	// 修复数据表
	public function repair($id = ''){
        if(empty($id)){
            return $this->error('请选择您要修复的数据表');
        }

        if(!is_array($id)) {
            $table[] = $id;
        }else{
            $table = $id;
        }

        $tables = implode('`,`', $table);
        $res = Db::query("REPAIR TABLE `{$tables}`");

        if($res){
            return $this->success('数据表修复完成');
        }

        return $this->error('数据表修复失败');
    }
	// 优化数据表
	public function optimize($id = ''){
		if($this->request->isAjax() != true){
			$this->error('404');
		}
		
		if(empty($id)){
            return $this->error('请选择您要优化的数据表');
        }

        if(!is_array($id)){
            $table[] = $id;
        }else{
            $table = $id;
        }

        $tables = implode('`,`', $table);
        $res = Db::query("OPTIMIZE TABLE `{$tables}`");
        if($res){
            return $this->success('数据表优化完成');
        }

        return $this->error('数据表优化失败');	
	}
	 /**
     * 删除备份
     * @author 橘子俊 <364666827@qq.com>
     * @return mixed
     */
    public function del($id = ''){
        if (empty($id)) {
            return $this->error('请选择您要删除的备份文件');
        }

        $name  = $id . '-*.sql*';
        $path = $this->backupPath.$name;
        array_map("unlink", glob($path));

        if(count(glob($path)) && glob($path)){
            return $this->error('备份文件删除失败，请检查权限');
        }
        
        return $this->success('备份文件删除成功');
    }
	
    /**
     * 恢复数据库 [参考原作者 麦当苗儿 <zuojiazi@vip.qq.com>]
     * @param string|array $ids 表名
     * @param integer $start 起始行数
     * @author 橘子俊 <364666827@qq.com>
     * @return mixed
     */
	public function import($id = ''){
		if(empty($id)){
            return $this->error('请选择您要恢复的备份文件');
        }
        $name  = $id . '-*.sql*';
        $path = $this->backupPath.$name;
		$files = glob($path);
        $list  = array();
		
		foreach($files as $name){
            $basename = basename($name);
            $match    = sscanf($basename, '%4s%2s%2s-%2s%2s%2s-%d');
            $gz       = preg_match('/^\d{8,8}-\d{6,6}-\d+\.sql.gz$/', $basename);
            $list[$match[6]] = array($match[6], $name, $gz);
        }

        ksort($list);
		
		$last = end($list);
		if(count($list) === $last[0]){
			foreach ($list as $item) {
				$config = [
                    'path'     => $this->backupPath,
                    'compress' => $item[2]
                ];
				$database = new dbOper($item, $config);
                $start = $database->import(0);
                // 导入所有数据
                while(0 !== $start){

                    if(false === $start){
                        return $this->error('数据恢复出错');
                    }

                    $start = $database->import($start[0]);
                }
			}
			return $this->success('数据恢复完成');
		}
		return $this->error('备份文件可能已经损坏，请检查');
	}
}
?>